package clw.wumi.views.list;

import clw.wumi.data.entity.Item;
import clw.wumi.data.entity.Place;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.IntegerField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.BeanValidationBinder;
import com.vaadin.flow.data.binder.Binder;

import java.util.List;

/**
 * @author chengliwei
 * @date 2023/4/25 16:00
 */
public class ItemForm extends FormLayout {
    TextField name = new TextField("名称");
    IntegerField num = new IntegerField("数量");
    ComboBox<Item> parentItem = new ComboBox<>("上级");
    ComboBox<Place> place = new ComboBox<>("地点");
    TextField desc = new TextField("描述");
    Button save = new Button("保存");
    Button delete = new Button("删除");
    Button close = new Button("关闭");

    Binder<Item> binder = new BeanValidationBinder<>(Item.class);

    public ItemForm(List<Place> places, List<Item> items) {
        addClassName("item-form");
        binder.bindInstanceFields(this);

        place.setItems(places);
        place.setItemLabelGenerator(Place::getName);
        place.setClearButtonVisible(true);
        place.addValueChangeListener(event -> {
            Place place = event.getValue();
            if (place != null) {
                ComboBox.ItemFilter<Item> itemFilter = (item, s) -> item.getPlace().getId().equals(place.getId());
                parentItem.setItems(itemFilter, items);
                parentItem.setItemLabelGenerator(Item::getName);
                parentItem.setClearButtonVisible(true);
            } else {
                parentItem.setItems(items);
                parentItem.setItemLabelGenerator(Item::getName);
                parentItem.setClearButtonVisible(true);
            }
        });

        parentItem.addValueChangeListener(event -> {
            Item item = event.getValue();
            if (item != null && place.getValue() == null) {
                place.setValue(item.getPlace());
            }
        });

        add(
                name,
                num,
                place,
                parentItem,
                desc,
                createButtonsLayout()
        );
    }

    private HorizontalLayout createButtonsLayout() {
        save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
        close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

        save.addClickShortcut(Key.ENTER);
        close.addClickShortcut(Key.ESCAPE);

        save.addClickListener(e -> validateAndSave());
        delete.addClickListener(e -> fireEvent(new DeleteEvent(this, binder.getBean())));
        close.addClickListener(e -> fireEvent(new CloseEvent(this)));
        return new HorizontalLayout(save, delete, close);
    }

    private void validateAndSave() {
        if (binder.isValid()) {
            fireEvent(new SaveEvent(this, binder.getBean()));
        }
    }

    public void setItem(Item item) {
        binder.setBean(item);
    }

    public abstract static class ItemFormEvent extends ComponentEvent<ItemForm> {
        private final Item item;

        protected ItemFormEvent(ItemForm source, Item item) {
            super(source, false);
            this.item = item;
        }

        public Item getItem() {
            return item;
        }
    }

    public static class SaveEvent extends ItemFormEvent {

        protected SaveEvent(ItemForm source, Item item) {
            super(source, item);
        }
    }

    public static class DeleteEvent extends ItemFormEvent {
        protected DeleteEvent(ItemForm source, Item item) {
            super(source, item);
        }
    }

    public static class CloseEvent extends ItemFormEvent {
        protected CloseEvent(ItemForm source) {
            super(source, null);
        }
    }

    public void addDeleteListener(ComponentEventListener<DeleteEvent> listener) {
        addListener(DeleteEvent.class, listener);
    }

    public void addSaveListener(ComponentEventListener<SaveEvent> listener) {
        addListener(SaveEvent.class, listener);
    }

    public void addCloseListener(ComponentEventListener<CloseEvent> listener) {
        addListener(CloseEvent.class, listener);
    }
}
